package com.freewater.javabase.demo.mutithread.synchronize;

import java.util.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ReentryLockDemo {

    public static void main(String[] args) throws InterruptedException {
        TaskQueue queue = new TaskQueue();
        List<Thread> workers = getWorkers(queue);
        Thread taskGenerator = taskGenerator(queue);
        taskGenerator.start();
        taskGenerator.join();
        Thread.sleep(1000);
        for (Thread worker : workers) {
            worker.interrupt();
        }
    }

    private static Thread taskGenerator(TaskQueue queue) {
        return new Thread(() -> {
            Random r = new Random();
            for (int i = 0; i < 10; i++) {
                String task = "t_" + r.nextDouble();
                queue.addTask(task);
                System.out.println("Thread " + Thread.currentThread().threadId() + " add Task: " + task);
                try {
                    Thread.sleep(50);
                } catch (InterruptedException ignored) {
                }
            }
        });
    }

    private static List<Thread> getWorkers(TaskQueue queue) {
        List<Thread> getTaskThreads = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            Thread t = new Thread(() -> {
                while (true) {
                    try {
                        String task = queue.getTask();
                        System.out.println("Thread " + Thread.currentThread().threadId() + " execute task: " + task);
                    } catch (InterruptedException e) {
                        break;
                    }
                }
            });
            t.start();
            getTaskThreads.add(t);
        }
        return getTaskThreads;
    }

    public static class TaskQueue {
        private final Queue<String> queue = new LinkedList<>();

        private final ReentrantLock lock = new ReentrantLock();

        private final Condition condition = lock.newCondition();

        public void addTask(String task) {
            lock.lock();
            try {
                queue.add(task);
                condition.signalAll();
            } finally {
                lock.unlock();
            }
        }

        public String getTask() throws InterruptedException {
            lock.lock();
            try {
                while (queue.isEmpty()) {// 使用while循环，每次拿到锁之后（进入方法拿到锁以及被唤醒后拿到锁）需要重新判断队列是不是空的
                    condition.await();
                }
                return queue.remove();
            } finally {
                lock.unlock();
            }
        }
    }
}
